project(ExampleVkApp C CXX)

# find vulkan
find_package(Vulkan REQUIRED)

# Compiling Shaders
#[[
  How to compiling shaders:
  1. get shader files(*.frag *.vert)
  2. write pre-defined spir-v variables to header
  3. call glslangValidator to generate c code
  4. combine all code to single source file
]]

##1
file(GLOB_RECURSE SHADER_FILES shaders/*.frag shaders/*.vert)

##2
set(SHADER_HEADER_FILE "${CMAKE_CURRENT_BINARY_DIR}/shader/shaders.hpp")
file(WRITE ${SHADER_HEADER_FILE} "// WARNING: GENERATE BY CMAKE, DO NOT MODIFY\n\n")
file(APPEND ${SHADER_HEADER_FILE} "#pragma once\n")
file(APPEND ${SHADER_HEADER_FILE} "#include<core/defines.hpp>\n")
file(APPEND ${SHADER_HEADER_FILE} "namespace core::shaders {\n")

set(SHADER_SPIR_BINARY_FILES)
set(SPIR_V_BIN_LIST ${CMAKE_CURRENT_BINARY_DIR}/shader_list.txt)
file(WRITE ${SPIR_V_BIN_LIST} "")

foreach (SHADER_FILE ${SHADER_FILES})
    get_filename_component(FULL_FILE_NAME ${SHADER_FILE} NAME)
    set(SPIR_V ${CMAKE_CURRENT_BINARY_DIR}/spir-v/${FULL_FILE_NAME})
    string(REPLACE "." "_" VAR_NAME ${FULL_FILE_NAME})
    string(TOLOWER ${VAR_NAME} VAR_NAME)
    file(APPEND ${SHADER_HEADER_FILE} "    extern const u8  ${VAR_NAME}_data[];\n")
    file(APPEND ${SHADER_HEADER_FILE} "    extern const u32 ${VAR_NAME}_length;\n")

    ##3
    add_custom_command(
            OUTPUT ${SPIR_V}
            COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/spir-v"
            COMMAND ${Vulkan_GLSLANG_VALIDATOR_EXECUTABLE} -V ${SHADER_FILE} -o ${SPIR_V}
            DEPENDS ${SHADER_FILE}
    )

    # add to shader_list.txt
    file(APPEND ${SPIR_V_BIN_LIST} "${SPIR_V}\n")

    list(APPEND SHADER_SPIR_BINARY_FILES ${SPIR_V})
endforeach ()
file(APPEND ${SHADER_HEADER_FILE} "}\n")

add_custom_target(
        CompileShaders
        DEPENDS ${SHADER_SPIR_BINARY_FILES}
)

# create empty cpp source file for spir-v data
set(SPIR_V_IMPL_FILENAME ${CMAKE_CURRENT_BINARY_DIR}/shaders_spirv.cpp)
file(TOUCH ${SPIR_V_IMPL_FILENAME})

add_custom_command(
        OUTPUT ${SPIR_V_IMPL_FILENAME}
        COMMAND spirv-merge ${SPIR_V_BIN_LIST} ${SPIR_V_IMPL_FILENAME}
        DEPENDS CompileShaders ${SHADER_SPIR_BINARY_FILES}
)

# Application
file(GLOB_RECURSE APP_SRCS *.h *.hpp *.c *.cpp shaders/*.*)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${APP_SRCS})
source_group("Generated Files" FILES ${SPIR_V_IMPL_FILENAME})
add_executable(${PROJECT_NAME} ${APP_SRCS} ${SPIR_V_IMPL_FILENAME})
target_precompile_headers(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/pch.hpp)
target_link_libraries(${PROJECT_NAME} PRIVATE glm glfw Vulkan::Vulkan quill::quill)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/shader)
add_dependencies(${PROJECT_NAME} CompileShaders)


set_target_properties(CompileShaders ${PROJECT_NAME} PROPERTIES FOLDER "Application")
